/*
 * TowerRedTwo.cs
 *
 * Created on December 19, 2007, 8:43 PM
 *
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 * Copyright (C) 2010       Mathijs Miermans
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;

using HexTD.hex;
using HexTD.sprite;
using HexTD.util;

namespace HexTD.tower
{
	public class TowerRedTwo : TowerBase
	{
		public static int price = 20000;
		public static int damage = 20000;
		public static float range = 8f;
		public static float spreadRadiusBase = 2f;
		public static float projectileSpeedBase = 0.4f;

		private int fireAt = -1;
		private COLOR damageColor = COLOR.RED;
		private int coolDown = 0;
		private int coolDownTime = 14;

		private Color transColor;
		private float projectileSpeed;
		private float spreadRadius;
		private float spreadRadius2;

		private List<Projectile> projectiles = new List<Projectile>();
#if PORT
		private Image[] projectileImg;
#endif

		/** Creates a new instance of TowerRedTwo */
		public TowerRedTwo(Context context, Hex hex)
			: base(TowerFactory.type.redTwo, price, damage, range)
		{
			this.lineColor = Colors.Red;
			this.transColor = Color.FromArgb(50, this.lineColor.R, this.lineColor.G, this.lineColor.B);
			this.doInit(context, hex);
		}

		public override void doTick(int gameTime)
		{
#if PORT
			if (this.coolDown > 0)
			{
				this.coolDown--;
			} else {
				int enemyNr = this.findEnemy(this.fireAt, false);
				this.fireAt = enemyNr;
            
				if (enemyNr >= 0) {
					Projectile p = new Projectile();
					p.target = this.context.enemies[enemyNr];
					p.x = this.xFloat;
					p.y = this.yFloat;
					this.projectiles.Add(p);
					this.coolDown = this.coolDownTime;
				}
			}
        
			for (int ip=this.projectiles.Count-1; ip >=0; ip--) {
				Projectile p = this.projectiles.get(ip);
				float dx, dy, r, factor;
				if (p.status == 0) {
					dx = p.target.getX() - p.x;
					dy = p.target.getY() - p.y;
					r = (float)Math.Sqrt(dx*dx + dy*dy);
					factor = this.projectileSpeed/r;
					if (factor < 1) {
						dx *= factor;
						dy *= factor;
						p.x += dx;
						p.y += dy;
					} else {
						// HIT!
						p.x = p.target.getX();
						p.y = p.target.getY();
						p.status = 1;
					}
				}
				if (p.status == 1) {
					p.targetsHit = this.findEnemiesInRange(p.x, p.y, this.spreadRadius);
					int damageBlast;
					float rs;
					EnemySprite enemy;
					for (int i=0; i < p.targetsHit.length; i++) {
						enemy = p.targetsHit[i];
						dx = p.x - enemy.getX();
						dy = p.y - enemy.getY();
						rs = (float)Math.Sqrt(dx*dx + dy*dy);
						damageBlast = Math.Round( this.damageCurrent * (1 - rs/this.spreadRadius) );
						enemy.doDamage(damageBlast, this.damageColor);
					}
					p.status++;
				} else if (p.status > 1) {
					p.target = null;
					this.projectiles.Remove(ip);
				}
			}
#endif
		}

		public override string getStatusString()
		{
			string retString = "";
			retString += "<h1>Red Tower 2</h1>" +
					"<p>" +
					"<b>Level:</b> " + (1 + this.level) + "<br>\n" +
					"<b>Damage:</b> " + this.damageText + "<br>\n" +
					"<b>Range:</b> " + this.rangeText + "<br>" +
					"</p>\n";
			return retString;
		}

		public override string getInfoString()
		{
			string retString = "";
			retString += "<h1>Red Tower 2</h1>" +
					"<p>" +
					"Tower firing fast homing projectiles with a small splash radius. " +
					"When the projectiles lose their target they continue to the last known location and detonate." +
					"<br>Strong against red enemies, very weak against green enemies." +
					"</p>" +
					"<p>" +
					"<b>Price:</b> " + price + "<br>" +
					"<b>Damage:</b> " + damageCurrent + " + splash<br>" +
					"<b>Range:</b> " + rangeCurrent + "<br>" +
					"<b>Refire rate:</b> 1.25/s" +
					"</p>";
			return retString;
		}

		protected override void generateShapes()
		{
#if PORT
			Cache cache = this.context.getCache();
        
			float width = this.context.hexPaintWidth;
			int shapeCount = 5;
			this.shapes = new Shape[shapeCount];
			this.shapes[0] = new Ellipse.Float(-0.3f*this.paintScale, -0.3f*this.paintScale, 0.6f*this.paintScale, 0.6f*this.paintScale);
			this.shapes[1] = new Ellipse.Float(-0.3f*this.paintScale, -0.3f*this.paintScale, 0.6f*this.paintScale, 0.6f*this.paintScale);
			this.shapes[2] = new Ellipse.Float(-1.0f*this.context.strokeScale, -1.0f*this.context.strokeScale, 2.0f*this.context.strokeScale, 2.0f*this.context.strokeScale);
			this.shapes[3] = new LineSegment.Float( width,  0.5f*this.paintScale,  0.3f*width,  0.15f*this.paintScale);
			this.shapes[4] = new LineSegment.Float(-width, -0.5f*this.paintScale, -0.3f*width, -0.15f*this.paintScale);
        
			this.shapeAction = new int[shapeCount];
			this.shapeAction[0] = 2;
			this.shapeAction[1] = 1;
			this.shapeAction[2] = 1;
			this.shapeAction[3] = 1;
			this.shapeAction[4] = 1;
        
			this.shapeColor = new Color[shapeCount];
			this.shapeColor[0] = this.transColor;
			this.shapeColor[1] = this.lineColor;
			this.shapeColor[2] = this.lineColor;
			this.shapeColor[3] = this.lineColor;
			this.shapeColor[4] = this.lineColor;
        
			this.strokes = new Brush[shapeCount];
			this.strokes[0] = new Brush(2.0f*this.context.strokeScale, Brush.CAP_ROUND, Brush.JOIN_BEVEL);
			this.strokes[1] = this.strokes[0];
			this.strokes[2] = this.strokes[0];
			this.strokes[3] = this.strokes[0];
			this.strokes[4] = this.strokes[0];
			this.spreadRadius = this.spreadRadiusBase;
			this.spreadRadius2 = this.spreadRadius * this.spreadRadius;
			this.projectileSpeed = projectileSpeedBase;
        
			if (cache.hasBufImgArr("Red2ProjImagArr")) {
				this.projectileImg = cache.getBufImgArr("Red2ProjImagArr");
			} else {
				float pWidth = width/10f;
				float pScale = this.paintScale/10f;
				int imgW = (int)(pScale*2)+2;
				int imgH = (int)(pScale*2)+2;
				this.projectileImg = new Image[3];
				float[,] pPoints = Geometry.createPolyCoords(pScale, (float)imgW/2, (float)imgH/2);
				RotateTransform atr = new RotateTransform();
				for (int i=0; i<this.projectileImg.length; i++) {
					atr.setToIdentity();
					atr.rotate(Math.PI * i * 2/6/3, (float)imgW/2, (float)imgH/2);
                
					this.projectileImg[i] = new Image(imgW, imgH, Image.TYPE_INT_ARGB_PRE);
					//GeneralPath polyHex = Geometry.coordsToGeneralPath(pPoints, true);
					Canvas g2 = this.projectileImg[i].createGraphics();
					g2.transform(atr);
					g2.setColor(this.lineColor);
					//g2.draw(polyHex);
					g2.draw(new LineSegment.Float(pPoints[0, 0], pPoints[0, 1], pPoints[3, 0], pPoints[3, 1]));
					g2.draw(new LineSegment.Float(pPoints[1, 0], pPoints[1, 1], pPoints[4, 0], pPoints[4, 1]));
					g2.draw(new LineSegment.Float(pPoints[2, 0], pPoints[2, 1], pPoints[5, 0], pPoints[5, 1]));
					g2.dispose();
				}
				cache.putBufImgArr("Red2ProjImagArr", this.projectileImg);
			}
#endif
		}

		public override void paintEffects(Canvas g2, int gameTime)
		{
#if PORT
			Brush defaultStroke = g2.getStroke();
        
			g2.setColor(this.lineColor);
			float pw = (float)this.projectileImg[0].getWidth() / 2f;
			float ph = (float)this.projectileImg[0].getHeight() / 2f;
			for (int ip=0; ip<this.projectiles.Count; ip++) {
				Projectile p = this.projectiles.get(ip);
				if (p.status == 0) {
					g2.drawImage(this.projectileImg[p.anim], Math.Round(p.x*paintScale+this.context.offsetX-pw), Math.Round(p.y*paintScale+this.context.offsetY-ph), null);
					p.anim++;
					if (p.anim >= this.projectileImg.length) {
						p.anim = 0;
					}
				} else {
					synchronized(p) {
						if (p.targetsHit != null) {
							for (int i=0; i<p.targetsHit.length; i++) {
								g2.draw(new LineSegment.Float( p.x*paintScale+this.context.offsetX, p.y*paintScale+this.context.offsetY, p.targetsHit[i].getPaintX(), p.targetsHit[i].getPaintY() ));
							}
						}
					}
				}
			}
        
			g2.setStroke(defaultStroke);
#endif
		}
	}
}